from flask import Blueprint, request, jsonify, make_response
from app.services.auth_service import AuthService, token_required, role_required
from app.models.user import User, UserPreference
from app.models.database import db
from app.utils.logger import logger
import io
import random
import string
from PIL import Image, ImageDraw, ImageFont
import base64
import redis
import os
import time

# Redis连接配置
redis_client = redis.from_url(os.environ.get('REDIS_URL', 'redis://localhost:6379/0'))

# 验证码有效期（秒）
CAPTCHA_EXPIRE = 300  # 5分钟

# 验证码存储前缀
CAPTCHA_PREFIX = 'captcha:'

# 创建认证路由蓝图
auth_bp = Blueprint('auth', __name__, url_prefix='/api/auth')


def generate_captcha_code(length=4):
    """生成随机验证码"""
    # 使用字母和数字，排除容易混淆的字符
    chars = string.ascii_uppercase + string.digits
    chars = ''.join(c for c in chars if c not in '0O1I')
    return ''.join(random.choice(chars) for _ in range(length))


def create_captcha_image(code):
    """创建验证码图片"""
    # 图片尺寸
    width, height = 120, 40
    
    # 创建图片对象，使用随机背景色
    bg_color = (random.randint(220, 250), random.randint(220, 250), random.randint(220, 250))
    image = Image.new('RGB', (width, height), bg_color)
    draw = ImageDraw.Draw(image)
    
    # 尝试加载字体，如果失败则使用默认字体
    try:
        font = ImageFont.truetype('arial.ttf', 24)
    except:
        font = ImageFont.load_default()
    
    # 在图片上绘制验证码
    for i, char in enumerate(code):
        # 随机字符颜色
        color = (random.randint(10, 100), random.randint(10, 100), random.randint(10, 100))
        # 随机位置和旋转角度
        x = 10 + i * 25 + random.randint(-2, 2)
        y = 5 + random.randint(-2, 2)
        angle = random.randint(-15, 15)
        
        # 创建旋转的文字
        temp_img = Image.new('RGBA', (30, 30), (255, 255, 255, 0))
        temp_draw = ImageDraw.Draw(temp_img)
        temp_draw.text((0, 0), char, font=font, fill=color)
        temp_img = temp_img.rotate(angle, expand=1)
        
        # 将旋转的文字粘贴到主图片
        paste_position = (x, y)
        image.paste(temp_img, paste_position, temp_img)
    
    # 添加干扰线
    for _ in range(3):
        line_color = (random.randint(100, 180), random.randint(100, 180), random.randint(100, 180))
        x1 = random.randint(0, width)
        y1 = random.randint(0, height)
        x2 = random.randint(0, width)
        y2 = random.randint(0, height)
        draw.line([(x1, y1), (x2, y2)], fill=line_color, width=1)
    
    # 添加干扰点
    for _ in range(50):
        dot_color = (random.randint(50, 150), random.randint(50, 150), random.randint(50, 150))
        x = random.randint(0, width)
        y = random.randint(0, height)
        draw.point((x, y), fill=dot_color)
    
    return image


@auth_bp.route('/captcha', methods=['GET'])
def get_captcha():
    """获取图形验证码"""
    try:
        # 生成验证码
        code = generate_captcha_code()
        
        # 生成随机ID用于关联验证码
        captcha_id = ''.join(random.choices(string.ascii_letters + string.digits, k=16))
        
        # 存储验证码到Redis，设置过期时间
        redis_client.setex(f'{CAPTCHA_PREFIX}{captcha_id}', CAPTCHA_EXPIRE, code.lower())
        
        # 创建验证码图片
        image = create_captcha_image(code)
        
        # 将图片转换为字节流
        img_byte_arr = io.BytesIO()
        image.save(img_byte_arr, format='PNG')
        img_byte_arr.seek(0)
        
        # 创建响应
        response = make_response(img_byte_arr.read())
        response.headers['Content-Type'] = 'image/png'
        response.headers['X-Captcha-ID'] = captcha_id  # 在响应头中返回验证码ID
        
        logger.info(f"生成验证码成功，ID: {captcha_id}")
        return response
        
    except Exception as e:
        logger.error(f"生成验证码失败: {str(e)}")
        return jsonify({'error': '生成验证码失败'}), 500


def verify_captcha(captcha_id, user_input):
    """验证验证码"""
    if not captcha_id or not user_input:
        return False
    
    try:
        # 从Redis获取验证码
        stored_code = redis_client.get(f'{CAPTCHA_PREFIX}{captcha_id}')
        if not stored_code:
            return False
        
        # 验证成功后删除验证码，防止重复使用
        redis_client.delete(f'{CAPTCHA_PREFIX}{captcha_id}')
        
        return stored_code.decode().lower() == user_input.lower()
    except Exception as e:
        logger.error(f"验证验证码失败: {str(e)}")
        return False

@auth_bp.route('/register', methods=['POST'])
def register():
    """用户注册接口"""
    try:
        data = request.get_json()
        
        # 验证必填字段
        required_fields = ['username', 'email', 'password']
        for field in required_fields:
            if field not in data or not data[field].strip():
                return jsonify({'error': f'缺少必填字段: {field}'}), 400
        
        # 注册用户
        result = AuthService.register_user(
            username=data['username'].strip(),
            email=data['email'].strip(),
            password=data['password'],
            role=data.get('role', 'user'),
            organization=data.get('organization'),
            department=data.get('department')
        )
        
        if result['success']:
            return jsonify({'message': '注册成功'}), 201
        else:
            return jsonify({'error': result['message']}), 400
            
    except Exception as e:
        logger.error(f"注册请求处理失败: {str(e)}")
        return jsonify({'error': '服务器内部错误'}), 500

@auth_bp.route('/login', methods=['POST'])
def login():
    """用户登录接口"""
    try:
        data = request.get_json()
        
        # 验证必填字段
        required_fields = ['username', 'password', 'captcha']
        for field in required_fields:
            if field not in data or not data[field]:
                return jsonify({'error': f'缺少{field}'}), 400
        
        # 验证验证码
        captcha_id = request.headers.get('X-Captcha-ID')
        if not verify_captcha(captcha_id, data['captcha']):
            return jsonify({'error': '验证码错误或已过期'}), 401
        
        # 用户登录
        result = AuthService.login_user(data['username'], data['password'])
        
        if result['success']:
            return jsonify({
                'token': result['token'],
                'user': result['user']
            }), 200
        else:
            return jsonify({'error': result['message']}), 401
            
    except Exception as e:
        logger.error(f"登录请求处理失败: {str(e)}")
        return jsonify({'error': '服务器内部错误'}), 500

@auth_bp.route('/profile', methods=['GET'])
@token_required
def get_profile():
    """获取当前用户资料"""
    try:
        user = request.current_user
        return jsonify(user.to_dict()), 200
    except Exception as e:
        logger.error(f"获取用户资料失败: {str(e)}")
        return jsonify({'error': '服务器内部错误'}), 500

@auth_bp.route('/profile', methods=['PUT'])
@token_required
def update_profile():
    """更新当前用户资料"""
    try:
        user = request.current_user
        data = request.get_json()
        
        # 更新用户资料
        result = AuthService.update_user_profile(
            user_id=user.id,
            **data
        )
        
        if result['success']:
            return jsonify(result['user']), 200
        else:
            return jsonify({'error': result['message']}), 400
            
    except Exception as e:
        logger.error(f"更新用户资料失败: {str(e)}")
        return jsonify({'error': '服务器内部错误'}), 500

@auth_bp.route('/password', methods=['PUT'])
@token_required
def update_password():
    """更新当前用户密码"""
    try:
        user = request.current_user
        data = request.get_json()
        
        # 验证必填字段
        required_fields = ['old_password', 'new_password']
        for field in required_fields:
            if field not in data or not data[field]:
                return jsonify({'error': f'缺少必填字段: {field}'}), 400
        
        # 更新密码
        result = AuthService.update_user_password(
            user_id=user.id,
            old_password=data['old_password'],
            new_password=data['new_password']
        )
        
        if result['success']:
            return jsonify({'message': '密码更新成功'}), 200
        else:
            return jsonify({'error': result['message']}), 400
            
    except Exception as e:
        logger.error(f"更新密码失败: {str(e)}")
        return jsonify({'error': '服务器内部错误'}), 500

@auth_bp.route('/preferences', methods=['GET'])
@token_required
def get_preferences():
    """获取用户首选项"""
    try:
        user = request.current_user
        
        # 获取用户首选项
        preference = UserPreference.query.filter_by(user_id=user.id).first()
        if not preference:
            # 创建默认首选项
            preference = UserPreference(user_id=user.id)
            db.session.add(preference)
            db.session.commit()
        
        return jsonify(preference.to_dict()), 200
        
    except Exception as e:
        logger.error(f"获取用户首选项失败: {str(e)}")
        return jsonify({'error': '服务器内部错误'}), 500

@auth_bp.route('/preferences', methods=['PUT'])
@token_required
def update_preferences():
    """更新用户首选项"""
    try:
        user = request.current_user
        data = request.get_json()
        
        # 获取或创建用户首选项
        preference = UserPreference.query.filter_by(user_id=user.id).first()
        if not preference:
            preference = UserPreference(user_id=user.id)
            db.session.add(preference)
        
        # 更新首选项
        for key, value in data.items():
            if hasattr(preference, key) and key != 'id':
                setattr(preference, key, value)
        
        db.session.commit()
        
        logger.info(f"用户首选项更新成功: {user.username}")
        return jsonify(preference.to_dict()), 200
        
    except Exception as e:
        db.session.rollback()
        logger.error(f"更新用户首选项失败: {str(e)}")
        return jsonify({'error': '服务器内部错误'}), 500

@auth_bp.route('/users', methods=['GET'])
@role_required('admin')
def get_users():
    """获取用户列表（仅管理员）"""
    try:
        # 获取分页参数
        page = int(request.args.get('page', 1))
        per_page = int(request.args.get('per_page', 10))
        
        # 查询用户列表
        users_pagination = User.query.paginate(page=page, per_page=per_page, error_out=False)
        
        # 转换为字典列表
        users = [user.to_dict() for user in users_pagination.items]
        
        return jsonify({
            'users': users,
            'total': users_pagination.total,
            'pages': users_pagination.pages,
            'current_page': page
        }), 200
        
    except Exception as e:
        logger.error(f"获取用户列表失败: {str(e)}")
        return jsonify({'error': '服务器内部错误'}), 500

@auth_bp.route('/users/<user_id>', methods=['PUT'])
@role_required('admin')
def update_user_admin(user_id):
    """管理员更新用户信息"""
    try:
        # 查找用户
        user = User.query.get(user_id)
        if not user:
            return jsonify({'error': '用户不存在'}), 404
        
        data = request.get_json()
        
        # 更新用户信息
        for key, value in data.items():
            if hasattr(user, key) and key not in ['id', 'password_hash', 'created_at', 'last_login_at']:
                setattr(user, key, value)
        
        db.session.commit()
        
        logger.info(f"管理员更新用户信息: {user.username}")
        return jsonify(user.to_dict()), 200
        
    except Exception as e:
        db.session.rollback()
        logger.error(f"管理员更新用户信息失败: {str(e)}")
        return jsonify({'error': '服务器内部错误'}), 500

@auth_bp.route('/logout', methods=['POST'])
@token_required
def logout():
    """用户登出（客户端删除token即可，服务端暂不实现token黑名单）"""
    try:
        logger.info(f"用户登出: {request.current_user.username}")
        return jsonify({'message': '登出成功'}), 200
    except Exception as e:
        logger.error(f"用户登出失败: {str(e)}")
        return jsonify({'error': '服务器内部错误'}), 500